{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python Practice 7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Open a `heights.csv` file with `np.loadtxt()` function. Be sure to set a correct \n",
    "delimiter in the `np.loadtxt()` function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "heights = # Put your code here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's plot the data distribution with `plt.hist()` function. Since we have a 2D array,\n",
    "we might need to convert it to th 1D array first by calling the `flatten()` **method** of an array.\n",
    "\n",
    "Generally speaking, method is usually a certain function that belongs to a class.\n",
    "This function acts directly on the object it was called by (in our case - numpy array). \n",
    "You can think of the following analogy:\n",
    "\n",
    "```python\n",
    "def mean(array):\n",
    "    return np.mean(array)\n",
    "```\n",
    "and\n",
    "```python\n",
    "array.mean()\n",
    "```\n",
    "are equivalent. The first one is a function that takes an array as an argument, while the second one is a method that belongs to the array class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Put your code here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We clearly see that something is wrong with the data. Let's try to find out\n",
    "the reason for that.\n",
    "\n",
    "First we might need to take a look, what are the exact values of those weird\n",
    "heights. To do that, we need to select all the heights that are less than\n",
    "10 (for instance) by using the `heights[heights < 10]` syntax."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Put your code here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It turns out that the values are just listed in meters, not in centimeters. \n",
    "To fix this issue, let's create the function that checks if the height is less than 3 meters\n",
    "and if it is, it multiplies the height by 100 to convert it to centimeters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fix_height_units(original_heights, threshold = 3.0):\n",
    "    heights = original_heights.copy() # We don't want to modify the original array, so we make a copy\n",
    "    # Put your code here\n",
    "    return heights"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also use the advanced numpy indexing to select all the heights that are less than 3 meters\n",
    "and multiply them by 100. In this example we can use the `heights[heights < 3] = heights[heights < 3] * 100` syntax.\n",
    "What happens is that `heights < 3` returns a boolean array of the same shape as the original array.\n",
    "Each element of this array is eigher `True` or `False` depending on whether the condition is met.\n",
    "Then we use this boolean array to select only the elements that are less than 3 meters and multiply them by 100."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fix_height_units_vectorized(original_heights, threshold = 3.0):\n",
    "    heights = original_heights.copy() # We don't want to modify the original array, so we make a copy\n",
    "    heights[heights < threshold] = heights[heights < threshold] * 100\n",
    "    return heights"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fixed_heights = fix_height_units(heights, threshold = 3.0) # This is our original function\n",
    "fixed_heights_vectorized = fix_height_units_vectorized(heights, threshold=3.0) # This is our vectorized function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.allclose(fixed_heights, fixed_heights_vectorized) # This will fail if the two arrays are not equal"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's test the following hypothesis: \n",
    "\n",
    "\"Is the true mean that represents the sample a given sample different from the population mean? Assume that the standard deviation of the data $\\sigma = 10$. Use a 95% confidence interval.\"\n",
    "\n",
    "To do that, we need to calculate first the population mean by using the `np.mean()` function over all the heights.\n",
    "Then we need to calculate the samples means by using the `np.mean()` function over each sample, or by providing\n",
    "the `axis=1` argument to the `np.mean()` function. \n",
    "\n",
    "Given that we know the standard deviation, the number of samples and the confidence level, we can use the formula\n",
    "for the z-score:\n",
    "\n",
    "$$z_{\\bar{x}} = \\frac{\\bar{x} - \\mu}{\\frac{\\sigma}{\\sqrt{n}}}$$\n",
    "\n",
    "where $\\bar{x}$ is the sample mean, $\\mu$ is the population mean, $\\sigma$ is the standard deviation and $n$ is the number of samples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Put your code here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Put your code here"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "metatrain",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
